﻿using Basic.HrGatewayModular.Interface;
using Basic.HrGatewayModular.Model.EmpLogin;
using Basic.HrRemoteModel.Emp;
using Basic.HrRemoteModel.Emp.Model;
using Basic.HrRemoteModel.EmpLogin;
using Basic.HrRemoteModel.EmpLogin.Model;
using WeDonekRpc.CacheClient.Interface;
using WeDonekRpc.Helper;
using WeDonekRpc.Modular;
using WeDonekRpc.Modular.Model;
using WeDonekRpc.ModularModel.Accredit.Model;

namespace Basic.HrGatewayModular.Services
{
    internal class EmpLoginService : IEmpLoginService
    {
        private readonly IAccreditService _Accredit;
        private readonly IUserOnlineService _OnlineUser;
        private readonly ICacheController _Cache;
        public EmpLoginService ( IAccreditService accredit,
            ICacheController cache,
            IUserOnlineService online )
        {
            this._Cache = cache;
            this._OnlineUser = online;
            this._Accredit = accredit;
        }
        public LoginDatum GetLoginDatum ( IUserState state )
        {
            long empId = state.ToEmpId();
            long comId = state.ToCompanyId();
            string key = $"LoginDatum_{empId}_{comId}";
            if ( !this._Cache.TryGet(key, out LoginDatum datum) )
            {
                datum = this._GetLoginDatum(empId, comId, state);
                _ = this._Cache.Set(key, datum, TimeSpan.FromMinutes(30));
            }
            return datum;
        }
        private async void _ClearCache ( long empId, long[] comId )
        {
            await Task.Factory.StartNew(() =>
            {
                comId.ForEach(c =>
                {
                    string key = $"LoginDatum_{empId}_{c}";
                    _ = this._Cache.Remove(key);
                });
            });

        }
        private LoginDatum _GetLoginDatum ( long empId, long comId, IUserState state )
        {
            EmpLoginDatum datum = new GetEmpLoginDatum
            {
                EmpId = empId,
                CompanyId = comId,
                Company = state.GetValue<long[]>("Company")
            }.Send();
            return new LoginDatum
            {
                CompanyId = state.ToCompanyId(),
                Company = datum.Company,
                CurSubSysId = datum.CurSubSysId,
                IsAdmin = datum.IsAdmin,
                Power = datum.Power,
                SubSystem = datum.SubSystem,
                Datum = new LoginUser
                {
                    CompantId = datum.CompanyId,
                    EmpId = empId,
                    EmpName = datum.Name,
                    UnitDept = state.ToUnitDept(),
                    DeptId = datum.DeptId,
                    UnitId = datum.UnitId,
                    HeadUri = datum.Head
                }
            };
        }
        public LoginDatum Switch ( IUserState state, long companyId )
        {
            long[] comId = state.GetValue<long[]>("Company");
            if ( !comId.Contains(companyId) )
            {
                throw new ErrorException("hr.user.no.power");
            }
            long curId = state.GetValue<long>("CompanyId");
            if ( curId == companyId )
            {
                return this.GetLoginDatum(state);
            }
            ComSwitchResult res = new EmpSwitchCompany
            {
                CompanyId = companyId,
                EmpId = state.ToEmpId()
            }.Send();
            state.SetPower(res.Power);
            state["CompanyId"] = companyId;
            state["IsAdmin"] = res.IsAdmin;
            state["DeptId"] = res.DeptId;
            if ( !state.SaveState() )
            {
                throw new ErrorException("hr.user.state.save.fail");
            }
            return this.GetLoginDatum(state);
        }
        private EmpLoginRes _GetLoginResult ( LoginResult result )
        {
            string applyId = "Hr_" + result.EmpId;
            UserState state = new UserState
            {
                Power = result.Power,
                Param = new Dictionary<string, StateParam>
                {
                    {"UserId",new StateParam(result.EmpId) },
                    {"UserType",new StateParam("emp") },
                    {"CompanyId",new StateParam(result.CompanyId)},
                    {"EntryComId",new StateParam(result.CompanyId) },
                    {"EmpName",new StateParam(result.EmpName) },
                    {"UnitDept",new StateParam(result.UnitDept) },
                    {"DeptId",new StateParam(result.DeptId)},
                    {"EntryUnitId",new StateParam(result.EntryUnitId)},
                    {"EntryDeptId",new StateParam(result.EntryDeptId)},
                    {"IsAdmin",new StateParam(result.IsAdmin)},
                    {"Company",new StateParam(result.Company) }
                }
            };
            string accreditId = this._Accredit.AddAccredit(applyId, state);
            this._ClearCache(result.EmpId, result.Company);
            return new EmpLoginRes
            {
                AccreditId = accreditId
            };
        }
        public EmpLoginRes EmpPwdLogin ( string loginName, string password, LoginState state )
        {
            LoginResult result = new EmpPwdLogin
            {
                LoginName = loginName,
                Password = password,
                LoginState = state
            }.Send();
            EmpLoginRes res = this._GetLoginResult(result);
            this._OnlineUser.Add(result, state, res.AccreditId);
            return res;
        }

        public void SetDatum ( long empId, PersonDatum obj )
        {
            new SetPersonDatum
            {
                Id = empId,
                Datum = obj
            }.Send();
        }
    }
}
